package com.study.java8;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.*;
import java.util.*;

/**
 * @author ysy
 * @version 1.0
 * @Title: StreamTest
 * @Note <b>ProjectName:</b> cusc-venus
 * <br><b>PackageName:</b> com.cusc.venus.acc.center.util
 * <br><b>ClassName:</b>
 * <br><b>Date:</b>
 *
 */
public class StreamTest {

    /**
     * 转换操作：map()，filter()，sorted()，distinct()；
     *
     * 合并操作：concat()，flatMap()；
     *
     * 并行处理：parallel()；
     *
     * 聚合操作：reduce()，collect()，count()，max()，min()，sum()，average()；
     *
     * 其他操作：allMatch(), anyMatch(), forEach()。
     **/
    public static void main(String[] args) {
        // 1. 创建stream
        // 1-1. Stream.of(可变参数)
        Stream<String> stream1 = Stream.of("A", "B", "C", "D");
        stream1.forEach(System.out::println);
        // 1-2. 基于数组或集合
        Stream<String> stream2 = Arrays.stream(new String[]{"A", "B", "C"});
        stream2.forEach(System.out::println);
        // java9中的api
//        Stream<String> stream3 = List.of("X", "Y", "Z").stream();
//        stream3.forEach(System.out::println);
        // 1-3. 基于Supplier
        Stream<Integer> natual = Stream.generate(new NatualSupplier());
        // 注意：无限序列必须先变成有限序列再打印:
        natual.limit(20).forEach(System.out::println);
        // 1-4. 基本类型的流对象：IntStream、LongStream、DoubleStream
        IntStream is = Arrays.stream(new int[]{1, 2, 3});
//        LongStream ls = List.of("1", "2", "3").stream().mapToLong(Long::parseLong);


        // 2. 【转换】使用map：参数为Function
        Stream<Integer> s = Stream.of(1, 2, 3, 4, 5);
        Stream<Integer> s2 = s.map(n -> n * n);
        Arrays.stream(new String[]{"  Apple ", " pear ", " ORANGE", " BaNaNa "}).map(String::trim).map(String::toLowerCase).forEach(System.out::println);
        Arrays.stream(new String[]{" 2019-12-31 ", "2020 - 01-09 ", "2020- 05 - 01 ", "2022 - 02 - 01", " 2025-01 -01"})
                .map(str -> str.replaceAll("\\s*", "")).map(LocalDate::parse).forEach(System.out::println);

        // 3. 【转换】使用filter：参数为Predicate
        IntStream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).filter(n -> n % 2 != 0).forEach(System.out::println);
        Stream.generate(new LocalDateSupplier()).limit(31).filter(ldt -> ldt.getDayOfWeek() == DayOfWeek.SATURDAY || ldt.getDayOfWeek() == DayOfWeek.SUNDAY).forEach(System.out::println);

        // 4. 【聚合】使用reduce
        // 0:初始值、acc:上次计算的结果、
        int sum = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).reduce(0, (acc, n) -> acc + n);
        System.out.println(sum); // 45
        // 若不设置初始值，则返回Optional
        Optional<Integer> opt = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).reduce((acc, n) -> acc + n);
        if (opt.isPresent()) {
            System.out.println(opt.get());
        }
        int product = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).reduce(1, (acc, n) -> acc * n);
        System.out.println(s); // 362880

        // 按行读取配置文件:
        List<String> props = Arrays.asList("profile=native", "debug=true", "logging=warn", "interval=500");
        Map<String, String> map = props.stream()
                // 把k=v转换为Map[k]=v:
                .map(kv -> {
                    String[] ss = kv.split("\\=", 2);
                    return Collections.singletonMap(ss[0], ss[1]);
                })
                // 把所有Map聚合到一个Map:
                .reduce(new HashMap<String, String>(), (m, kv) -> {
                    m.putAll(kv);
                    return m;
                });
                // 打印结果:
                map.forEach((k, v) -> {
                    System.out.println(k + " = " + v);
                });


        // 5. 输出为数组:toArray
        List<String> list = Arrays.asList("Apple", "Banana", "Orange");
        String[] array = list.stream().toArray(String[]::new);

        // 6. 输出为map:collect + Collectors.toMap
        Stream<String> stream = Stream.of("APPL:Apple", "MSFT:Microsoft");
        Map<String, String> map1 = stream.collect(Collectors.toMap(str1 -> str1.substring(0, str1.indexOf(':')), str1 -> str1.substring(str1.indexOf(':') + 1)));
        System.out.println(map);

        // 7. 分组输出：collect + Collectors.groupingBy
        list = Arrays.asList("Apple", "Banana", "Blackberry", "Coconut", "Avocado", "Cherry", "Apricots");
        Map<String, List<String>> groups = list.stream().collect(Collectors.groupingBy(str2 -> str2.substring(0, 1), Collectors.toList()));
        System.out.println(groups);

        // 8. 排序：sorted
        list = Arrays.asList("Orange", "apple", "Banana").stream().sorted().collect(Collectors.toList());
        System.out.println(list);

        // 9. 去重：distinct
        list = Arrays.asList("A", "B", "A", "C", "B", "D").stream().distinct().collect(Collectors.toList());
        System.out.println(list);

        // 10. 截取：skip、limit
        list = Arrays.asList("A", "B", "C", "D", "E", "F").stream().skip(2).limit(3).collect(Collectors.toList());
        System.out.println(list);

        // 11. 合并:concat
        Stream<String> s3 = Arrays.asList("A", "B", "C").stream();
        Stream<String> s4 = Arrays.asList("D", "E").stream();
        Stream<String> s5 = Stream.concat(s3, s4);
        System.out.println(s5.collect(Collectors.toList()));

        // 12. flatMap：将每个元素映射为stream，合并为一个新的stream
        Stream<List<Integer>> s6 = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6), Arrays.asList(7, 8, 9));
        Stream<Integer> i = s6.flatMap(li -> li.stream());
        System.out.println("12: " + i.collect(Collectors.toList()));

        // 13. 并行：parallel
        Stream<String> s7 = Arrays.asList("Orange", "apple", "Banana").stream();
        String[] result = s7.parallel().sorted().toArray(String[]::new);

        // 14. count、max、min
        long count = Arrays.asList(8,10,1,6).stream().count();
        Optional<Integer> max = Arrays.asList(8,10,1,6).stream().max(Integer::compareTo);
        if (max.isPresent()) {
            System.out.println("14.最大的数：" + max.get());
        }
        Optional<Integer> min = Arrays.asList(8,10,1,6).stream().min(Integer::compare);
        if (min.isPresent()) {
            System.out.println("15.最小的数：" + min.get());
        }
        // 15. allMatch、anyMatch

        // 16. foreach

    }

    static class LocalDateSupplier implements Supplier<LocalDate> {
        LocalDate start = LocalDate.of(2020, 1, 1);
        int n = -1;
        public LocalDate get() {
            n++;
            return start.plusDays(n);
        }
    }
    static class NatualSupplier implements Supplier<Integer> {
        int n = 0;
        public Integer get() {
            return ++n;
        }
    }

}
